import { spawn, ChildProcess } from 'child_process';
import * as vscode from 'vscode';
import { ToolResult } from '../types/types';

/**
 * 命令执行配置
 */
export interface CommandExecutionOptions {
    /** 工作目录 */
    cwd?: string;
    /** 环境变量 */
    env?: Record<string, string>;
    /** 超时时间（毫秒），默认30秒 */
    timeout?: number;
    /** * Shell类型 
     * 支持: 'cmd', 'powershell', 'bash' 或自定义路径
     * 如果未指定，Windows 默认 'powershell'，Linux/Mac 默认 'bash'
     */
    shell?: string | boolean;
}

/**
 * 命令执行结果
 */
export interface CommandExecutionResult {
    stdout: string;
    stderr: string;
    exitCode: number | null;
    timedOut: boolean;
    duration: number;
}

/**
 * 正在运行的进程管理
 */
class ProcessManager {
    private processes = new Map<string, ChildProcess>();

    register(callId: string, process: ChildProcess): void {
        this.processes.set(callId, process);
    }

    kill(callId: string): boolean {
        const process = this.processes.get(callId);
        if (process && !process.killed) {
            process.kill('SIGTERM'); // Windows 上 node 会自动转换为 taskkill
            this.processes.delete(callId);
            return true;
        }
        return false;
    }

    cleanup(callId: string): void {
        this.processes.delete(callId);
    }

    killAll(): void {
        for (const [callId, process] of this.processes) {
            if (!process.killed) {
                process.kill('SIGTERM');
            }
        }
        this.processes.clear();
    }
}

const processManager = new ProcessManager();

/**
 * 执行命令并返回结果
 */
export async function executeCommand(
    command: string,
    options: CommandExecutionOptions = {},
    callId?: string
): Promise<CommandExecutionResult> {
    const startTime = Date.now();
    const timeout = options.timeout || 30000;
    
    const cwd = options.cwd || vscode.workspace.workspaceFolders?.[0]?.uri.fsPath || process.cwd();
    
    const env = { 
        ...process.env, 
        ...options.env,
        ...(process.platform === 'win32' ? { PYTHONIOENCODING: 'utf-8' } : {})
    };

    return new Promise((resolve) => {
        let stdout = '';
        let stderr = '';
        let timedOut = false;
        let exitCode: number | null = null;

        let finalCommand = command;
        // 默认使用系统 shell (Windows: cmd.exe, Unix: /bin/sh)
        // 我们通过构造不同的 finalCommand 来调用不同的 shell 引擎
        let spawnShell: string | boolean = true; 

        if (process.platform === 'win32') {
            // Windows 平台 Shell 路由逻辑
            const requestedShell = typeof options.shell === 'string' ? options.shell.toLowerCase() : 'powershell';

            if (requestedShell === 'cmd' || requestedShell === 'cmd.exe') {
                // CMD 模式: 使用 PowerShell 包装 CMD 命令并强制 UTF-8 输出
                // 这样可以确保输出流是 UTF-8 编码,避免 GBK 乱码问题
                const escapedCommand = command.replace(/"/g, '`"');
                finalCommand = `powershell.exe -NoProfile -Command "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; cmd /c '${command}'"`;
                spawnShell = true; // 使用默认shell调用PowerShell
            } else if (requestedShell === 'bash') {
                // Bash 模式 (Git Bash / WSL): bash -c "command"
                // 需要转义内部的双引号
                const escapedCommand = command.replace(/"/g, '\\"');
                finalCommand = `bash -c "${escapedCommand}"`;
                spawnShell = true; // 使用默认shell调用bash
            } else {
                // PowerShell 模式 (默认): powershell -Command "..."
                // 强制 UTF-8 编码以解决乱码问题
                const escapedCommand = command.replace(/"/g, '`"');
                finalCommand = `powershell.exe -NoProfile -Command "[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; ${escapedCommand}"`;
                spawnShell = true; // 使用默认shell调用powershell
            }
        } else {
            // 非 Windows 平台
            if (typeof options.shell === 'string') {
                // 如果用户指定了 shell (如 '/bin/zsh'), 直接传递给 spawn
                spawnShell = options.shell;
            } else {
                // 默认使用 bash
                spawnShell = '/bin/bash';
            }
        }

        // 执行命令
        const childProcess = spawn(finalCommand, {
            cwd,
            env,
            shell: spawnShell,
            windowsHide: true
        });

        if (callId) {
            processManager.register(callId, childProcess);
        }

        const timeoutId = setTimeout(() => {
            timedOut = true;
            if (!childProcess.killed) {
                childProcess.kill();
                stderr += '\n[Timeout] Command execution timed out.';
            }
        }, timeout);

        // 🟢 统一使用 UTF-8 解码输出流
        childProcess.stdout?.on('data', (data: Buffer) => {
            stdout += data.toString('utf8');
        });

        childProcess.stderr?.on('data', (data: Buffer) => {
            stderr += data.toString('utf8');
        });

        childProcess.on('close', (code: number | null) => {
            clearTimeout(timeoutId);
            exitCode = code;
            const duration = Date.now() - startTime;
            
            if (callId) {
                processManager.cleanup(callId);
            }

            resolve({
                stdout: stdout.trim(),
                stderr: stderr.trim(),
                exitCode,
                timedOut,
                duration
            });
        });

        childProcess.on('error', (err: Error) => {
            clearTimeout(timeoutId);
            stderr += `\n[Error] Failed to start process: ${err.message}`;
            exitCode = -1;
            const duration = Date.now() - startTime;
            
            if (callId) {
                processManager.cleanup(callId);
            }

            resolve({
                stdout: stdout.trim(),
                stderr: stderr.trim(),
                exitCode,
                timedOut: false,
                duration
            });
        });
    });
}

/**
 * 执行命令工具（用于工具调用）
 */
export async function executeCommandTool(
    args: Record<string, any>,
    callId: string
): Promise<ToolResult> {
    const command = args.command as string;
    const cwd = args.cwd as string | undefined;
    const timeout = args.timeout as number | undefined;
    const shell = args.shell as string | undefined; // 获取 shell 参数

    if (!command) {
        return {
            callId,
            success: false,
            output: '',
            error: 'Missing required parameter: command',
            exitCode: -1,
            duration: 0
        };
    }

    try {
        const result = await executeCommand(
            command,
            { cwd, timeout, shell }, // 传递 shell 参数
            callId
        );

        let output = '';
        if (result.stdout) output += result.stdout;
        if (result.stderr) output += (output ? '\n\n' : '') + '[STDERR]\n' + result.stderr;

        const success = result.exitCode === 0 && !result.timedOut;

        return {
            callId,
            success,
            output: output || '[No Output]',
            error: result.timedOut ? 'Execution Timed Out' : (success ? undefined : `Process exited with code ${result.exitCode}`),
            exitCode: result.exitCode ?? -1,
            duration: result.duration
        };
    } catch (error) {
        return {
            callId,
            success: false,
            output: '',
            error: `Execution Error: ${error instanceof Error ? error.message : String(error)}`,
            exitCode: -1,
            duration: 0
        };
    }
}

export function killCommand(callId: string): boolean {
    return processManager.kill(callId);
}

export function cleanupAllProcesses(): void {
    processManager.killAll();
}